Don't recurse so often in the dependency graph
authorAlex Crichton <alex@alexcrichton.com>
Fri, 29 May 2015 20:35:29 +0000 (13:35 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 3 Jun 2015 01:05:47 +0000 (18:05 -0700)
Prior to this commit the entire dependency tree would be traversed many, many
times as the short circuits weren't applying fast enough. This commit modifies
the recursion to only happen if the target in question was actually compiled.

This commit saw a noop build time for Servo drop from 4.5s to 2.5s.

src/cargo/ops/cargo_rustc/custom_build.rs
src/cargo/ops/cargo_rustc/mod.rs

index 1f7d427cba2bacf3a79f2d9ca3c62959e2772bf2..8518f728f0e42a640eda4407eabee0345b73a433 100644 (file)
@@ -7,7 +7,7 @@ use std::sync::Mutex;
 
 use core::{Package, Target, PackageId, PackageSet};
 use util::{CargoResult, human, Human};
-use util::{internal, ChainError};
+use util::{internal, ChainError, profile};
 
 use super::job::Work;
 use super::{fingerprint, process, Kind, Context, Platform};
@@ -41,6 +41,8 @@ pub struct BuildState {
 /// only run once (not twice).
 pub fn prepare(pkg: &Package, target: &Target, req: Platform,
                cx: &mut Context) -> CargoResult<(Work, Work, Freshness)> {
+    let _p = profile::start(format!("build script prepare: {}/{}",
+                                    pkg, target.name()));
     let kind = match req { Platform::Plugin => Kind::Host, _ => Kind::Target, };
     let (script_output, build_output) = {
         (cx.layout(pkg, Kind::Host).build(pkg),
index d10ab0efcd75932d19437597d23eef2dececfe13..579e5a99850db38c876aa93e83b37e13caf79ec1 100644 (file)
@@ -187,7 +187,6 @@ fn compile<'a, 'cfg>(targets: &[(&'a Target, &'a Profile)],
                      cx: &mut Context<'a, 'cfg>,
                      jobs: &mut JobQueue<'a>) -> CargoResult<()> {
     debug!("compile_pkg; pkg={}", pkg);
-    let profiling_marker = profile::start(format!("preparing: {}", pkg));
 
     // For each target/profile run the compiler or rustdoc accordingly. After
     // having done so we enqueue the job in the right portion of the dependency
@@ -200,6 +199,8 @@ fn compile<'a, 'cfg>(targets: &[(&'a Target, &'a Profile)],
             continue
         }
 
+        let profiling_marker = profile::start(format!("preparing: {}/{}",
+                                                      pkg, target.name()));
         let work = if profile.doc {
             let rustdoc = try!(rustdoc(pkg, target, profile, cx));
             vec![(rustdoc, Kind::Target)]
@@ -232,6 +233,12 @@ fn compile<'a, 'cfg>(targets: &[(&'a Target, &'a Profile)],
             };
             dst.push((Job::new(dirty, fresh), freshness));
         }
+        drop(profiling_marker);
+
+        // Be sure to compile all dependencies of this target as well.
+        for &(pkg, target, p) in cx.dep_targets(pkg, target, profile).iter() {
+            try!(compile(&[(target, p)], pkg, cx, jobs));
+        }
 
         // If this is a custom build command, we need to not only build the
         // script but we also need to run it. Note that this is a little nuanced
@@ -280,15 +287,6 @@ fn compile<'a, 'cfg>(targets: &[(&'a Target, &'a Profile)],
             jobs.queue(pkg, Stage::BuildCustomBuild).pop();
         }
     }
-    drop(profiling_marker);
-
-    // Be sure to compile all dependencies of this target as well. Don't recurse
-    // if we've already recursed, however.
-    for &(target, profile) in targets {
-        for &(pkg, target, p) in cx.dep_targets(pkg, target, profile).iter() {
-            try!(compile(&[(target, p)], pkg, cx, jobs));
-        }
-    }
 
     Ok(())
 }